package com.lelouch.bestpractice.mongorepository.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.lelouch.bestpractice.mongorepository.common.ServerResponse;
import com.lelouch.bestpractice.mongorepository.domain.WetlandBasicEntity;
import com.lelouch.bestpractice.mongorepository.exception.ParamException;
import com.lelouch.bestpractice.mongorepository.param.WetlandBasicEntityParam;
import com.lelouch.bestpractice.mongorepository.repository.WetlandBasicEntityRepository;
import com.lelouch.bestpractice.mongorepository.service.WetlandBasicEntityServive;
import com.lelouch.bestpractice.mongorepository.tools.BeanValidatorUtil;
import com.lelouch.bestpractice.mongorepository.tools.MapServerFromXmlTool;
import com.lelouch.bestpractice.mongorepository.tools.UploadExcelUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.bson.Document;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.*;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;


import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Optional;
import java.util.stream.Collectors;

import static org.springframework.data.mongodb.core.aggregation.Aggregation.group;
import static org.springframework.data.mongodb.core.aggregation.Aggregation.newAggregation;
import static org.springframework.data.mongodb.core.aggregation.Aggregation.project;

/**
 * @author lcy
 * @create 2018-09-12 15:07
 */
@Service
@Slf4j
public class WetlandbasicEntityServiceImpl implements WetlandBasicEntityServive {
    @Autowired
    private WetlandBasicEntityRepository wetlandBasicEntityRepository;
    @Autowired
    private MongoTemplate mongoTemplate;
    @Value("${arcgis.server.ip}")
    private String arcgisServerIp;
    @Value("${arcgis.server.port}")
    private String arcgisServerPort;

    private final String COLLECTION = "WetlandBasicEntity";

    @Override
    public List<String> findWetlandPicturesByWetlandIds(List<String> wetlandIds) {
        List<WetlandBasicEntity> wetlandBasicEntities = wetlandBasicEntityRepository.findByIdIn(wetlandIds);
        List<List<String>> pictures = wetlandBasicEntities.stream()
                .map(WetlandBasicEntity::getWlin_picture)
                .collect(Collectors.toList());
        List<String> finalPictures = Lists.newArrayList();
        for (List<String> stringList : pictures) {
            finalPictures.addAll(stringList);
        }

        return finalPictures;
    }

    @Override
    public WetlandBasicEntity findWetlandByWetlandId(String wetlandId) {
        try {
            return wetlandBasicEntityRepository.findById(wetlandId).get();
        }catch (NoSuchElementException e){
            e.printStackTrace();
            return null;
        }

    }

    @Override
    public boolean checkWetlandNameExists(String wetlandName) {
        return wetlandBasicEntityRepository.existsByNameEquals(wetlandName);
    }

    @Override
    public WetlandBasicEntity findWetlandByWetlandName(String wetlandName) {
        return wetlandBasicEntityRepository.findByName(wetlandName);
    }

    /**
     * 如果有一个参数为空的话，则该参数就不参与查询
     *
     * @return
     */
    @Override
    public ServerResponse<List<WetlandBasicEntity>> findWetlandsByMultiConditions(String queryString) {
        //如果传递过来有值的话，应该执行精确查询
        JSONObject queryJsonObject = JSON.parseObject(queryString);
        if (queryJsonObject.size() == 0) {
            return ServerResponse.createBySuccess(wetlandBasicEntityRepository.findAll());
        }
        Query query = new Query();
        for (String key : queryJsonObject.keySet()) {
            Object value = queryJsonObject.get(key);
            if (!StringUtils.isBlank((String) value)) {
                query.addCriteria(Criteria.where(key).is(value));
            }
        }
        return ServerResponse.createBySuccess(
                mongoTemplate.find(query, WetlandBasicEntity.class, COLLECTION));
    }

    //@Override
    //public List<WetlandStatisticsResultByCityEntity> statisticsByCity() {
    //    Aggregation aggregation = newAggregation(
    //            group("wlin_city").push("wlin_name").as("wetlandNameList"),
    //            project("wetlandNameList").and("city").previousOperation()
    //    );
    //
    //    AggregationResults<WetlandStatisticsResultByCityEntity> result = mongoTemplate.aggregate(aggregation, COLLECTION, WetlandStatisticsResultByCityEntity.class);
    //    List<WetlandStatisticsResultByCityEntity> resultList = result.getMappedResults();
    //    return resultList;
    //}

    @Override
    public List<Document> getWetlandCountsByLevel() {
        Aggregation aggregation = newAggregation(
                group("wlin_protection_level").count().as("wetlandNum"),
                project("wetlandNum").and("level").previousOperation()
        );

        //这里最好使用Document来接受聚合过的数据
        AggregationResults<Document> result = mongoTemplate.aggregate(aggregation, COLLECTION, Document.class);
        List<Document> resultList = result.getMappedResults();
        log.info("根据level分类得到的保护主体个数聚合的结果:{}", resultList);
        //log.info(resultList.get(0).getString("level"));
        return resultList;
    }

    @Override
    public List<Document> getWetlandAreasByLevel() {
        //sum()函数需要注意sum的字段是double或者int等数值类型的字段
        Aggregation aggregation = newAggregation(
                group("wlin_protection_level").sum("wlin_scale").as("wetlandArea"),
                project("wetlandArea").and("level").previousOperation()
        );

        //这里最好使用Document来接受聚合过的数据
        AggregationResults<Document> result = mongoTemplate.aggregate(aggregation, COLLECTION, Document.class);
        List<Document> resultList = result.getMappedResults();
        log.info("根据level分类得到的保护主体面积聚合的结果:{}", resultList);
        //log.info(resultList.get(0).getString("level"));
        return resultList;
    }

    @Override
    public List<WetlandBasicEntity> getAllWetlandsByPage(Integer start, Integer length, String orderName, String order) {
        Sort sort = null;
        if (StringUtils.equals("asc", order)) {
            sort = new Sort(Sort.Direction.ASC, orderName);
        } else {
            sort = new Sort(Sort.Direction.DESC, orderName);
        }
        Pageable pageable = PageRequest.of(start, length, sort);
        Page<WetlandBasicEntity> wetlandBasicEntities = wetlandBasicEntityRepository.findAll(pageable);
        return wetlandBasicEntities.getContent();

    }

    @Override
    public WetlandBasicEntity addWetlandBasicInfo(WetlandBasicEntityParam wetlandBasicEntityParam) {
        //先进行数据校验
        BeanValidatorUtil.check(wetlandBasicEntityParam);
        //检查保护主体名称是否重复
        if (checkWetlandNameExists(wetlandBasicEntityParam.getName())) {
            throw new ParamException("已存在该保护主体名称，请重新命名！");
        }
        //将前端的传来的数据结构转化成数据库中保护主体的数据结构
        WetlandBasicEntity wetlandBasicEntity = new WetlandBasicEntity();
        BeanUtils.copyProperties(wetlandBasicEntityParam, wetlandBasicEntity);
        //根据gis_mapserver的名字需找对应图层的地址组
        List<String> urls = MapServerFromXmlTool.findMapServerUrls(wetlandBasicEntityParam.getWlin_gis_mapserver(), arcgisServerIp, arcgisServerPort);
        if (CollectionUtils.isEmpty(urls)) {
            wetlandBasicEntity.setWlin_gis_mapserver_url(StringUtils.EMPTY);
        } else {
            wetlandBasicEntity.setWlin_gis_mapserver_url(urls.get(0));
        }
        wetlandBasicEntity.setLevel("其他");
        wetlandBasicEntity.setForm("其他");
        return wetlandBasicEntityRepository.save(wetlandBasicEntity);
    }

    @Override
    public ServerResponse deleteWetlandByWetlandId(String wetlandId) {
        if (StringUtils.isBlank(wetlandId)) {
            throw new ParamException("删除保护主体传来的id为空");
        }
        Optional<WetlandBasicEntity> wetlandBasicEntity = wetlandBasicEntityRepository.findById(wetlandId);
        log.info("{}", wetlandBasicEntity);
        //根据isPresent来判断wetlandBasicEntity是否存在
        if (!wetlandBasicEntity.isPresent()) {
            throw new ParamException("不存在该保护主体");
        }
        //todo 根据保护主体名字去其他的实体中寻找实体集合，如果有则代表该保护主体下面有下级，是不可以删除的
        try {
            wetlandBasicEntityRepository.deleteById(wetlandId);
            if (!wetlandBasicEntityRepository.existsById(wetlandId)) {
                return ServerResponse.createBySuccess("删除保护主体成功");
            }
        } catch (Exception e) {
            return ServerResponse.createByError("删除保护主体出现错误,请联系管理员！");
        }
        return ServerResponse.createByError("删除保护主体出现错误,请联系管理员！");
    }

    @Override
    public ServerResponse<List<WetlandBasicEntity>> findAllWetlands() {
        List<WetlandBasicEntity> wetlandBasicEntities = wetlandBasicEntityRepository.findAll();
        return ServerResponse.createBySuccess(wetlandBasicEntities);
    }

    @Override
    public ServerResponse<List<WetlandBasicEntity>> findWetlandsByWetlandIds(List<String> wetlandIds) {
        //List<WetlandBasicEntity> wetlandBasicEntities = wetlandBasicEntityRepository.findByIdIn(wetlandIds);
        return ServerResponse.createBySuccess(wetlandBasicEntityRepository.findByIdIn(wetlandIds));
    }

    @Override
    public ServerResponse<List<WetlandBasicEntity>> findWetlandsByFuzzySearch(String queryString) {
        JSONObject queryJsonObject = JSON.parseObject(queryString);

        if (queryJsonObject.size() == 0) {
            return ServerResponse.createBySuccess(wetlandBasicEntityRepository.findAll());
        }
        Query query = new Query();
        for (String key : queryJsonObject.keySet()) {
            Object value = queryJsonObject.get(key);
            if (!StringUtils.isBlank((String) value)) {
                query.addCriteria(Criteria.where(key).regex(".*?" + value + ".*"));
            }
        }

        return ServerResponse.createBySuccess(
                mongoTemplate.find(query, WetlandBasicEntity.class, COLLECTION));
    }


    @Override
    public ServerResponse uploadWetlandsExcel(MultipartFile uploadExcel) throws IOException {

        List<WetlandBasicEntity> uploadWetlandBasicEntityListOld = Lists.newArrayList();
        //try {
            uploadWetlandBasicEntityListOld =
                    UploadExcelUtil.assembleWetlandBasicEntityListFormExcel(uploadExcel);
        //}
        //catch (Exception e) {
        //    e.printStackTrace();
        //    return ServerResponse.createByError(e.getMessage());
        //}
        List<WetlandBasicEntity> uploadWetlandBasicEntityListNew = Lists.newArrayList();
        List<WetlandBasicEntity> allWetlandBasicEntityList = wetlandBasicEntityRepository.findAll();
        Map<String, WetlandBasicEntity> allWetlandBasicEntityMap = Maps.newHashMap();
        for (WetlandBasicEntity wbe : allWetlandBasicEntityList) {
            allWetlandBasicEntityMap.put(wbe.getName(), wbe);
        }
        for (WetlandBasicEntity wbe : uploadWetlandBasicEntityListOld) {
            if (allWetlandBasicEntityMap.get(wbe.getName()) != null) {
                WetlandBasicEntity wetlandBasicEntityNew = allWetlandBasicEntityMap.get(wbe.getName());
                wetlandBasicEntityNew.setWlin_gis_mapserver(wbe.getWlin_gis_mapserver());
                wetlandBasicEntityNew.setWlin_sectorization_mapserver(wbe.getWlin_sectorization_mapserver());
                wetlandBasicEntityNew.setWlin_location_gis_mapserver(wbe.getWlin_location_gis_mapserver());
                wetlandBasicEntityNew.setWlin_soil_gis_mapserver(wbe.getWlin_soil_gis_mapserver());
                wetlandBasicEntityNew.setWlin_type_gis_mapserver(wbe.getWlin_type_gis_mapserver());
                wetlandBasicEntityNew.setWlin_latitude(wbe.getWlin_latitude());
                wetlandBasicEntityNew.setWlin_longitude(wbe.getWlin_longitude());
                wetlandBasicEntityNew.setProvince(wbe.getProvince());
                wetlandBasicEntityNew.setCity(wbe.getCity());
                wetlandBasicEntityNew.setDistrict(wbe.getDistrict());
                wetlandBasicEntityNew.setWlin_scale(wbe.getWlin_scale());
                wetlandBasicEntityNew.setWlin_overview(wbe.getWlin_overview());
                wetlandBasicEntityNew.setWlin_official_area(wbe.getWlin_official_area());
                wetlandBasicEntityNew.setWlin_gis_area(wbe.getWlin_gis_area());
                wetlandBasicEntityNew.setWlin_location_gis_layer(wbe.getWlin_location_gis_layer());
                wetlandBasicEntityNew.setWlin_location_des(wbe.getWlin_location_des());
                wetlandBasicEntityNew.setWlin_border_des(wbe.getWlin_border_des());
                wetlandBasicEntityNew.setLevel(wbe.getLevel());
                wetlandBasicEntityNew.setForm(wbe.getForm());
                wetlandBasicEntityNew.setWlin_protection_object(wbe.getWlin_protection_object());
                wetlandBasicEntityNew.setWlin_bulid_date(wbe.getWlin_bulid_date());
                wetlandBasicEntityNew.setWlin_sectorization_layer(wbe.getWlin_sectorization_layer());
                wetlandBasicEntityNew.setWlin_type_gis_layer(wbe.getWlin_type_gis_layer());
                wetlandBasicEntityNew.setWlin_type_infos(wbe.getWlin_type_infos());
                wetlandBasicEntityNew.setWlin_type(wbe.getWlin_type());
                uploadWetlandBasicEntityListNew.add(wetlandBasicEntityNew);
            } else {
                uploadWetlandBasicEntityListNew.add(wbe);
            }
        }
        try {
            wetlandBasicEntityRepository.saveAll(uploadWetlandBasicEntityListNew);
            return ServerResponse.createBySuccess("上传保护主体数据成功!");
        } catch (Exception e) {
            return ServerResponse.createBySuccess("上传保护主体数据失败，请联系管理员!");
        }
    }


}
